package org.forever.view
{
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.collections.ArrayList;
	import mx.core.UIComponent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.UIDUtil;
	
	import spark.components.BorderContainer;
	import spark.components.SkinnableContainer;

	/**
	 * 折线的实现(初始化状态是3点两边)
	 */
	public class BrokenLine extends UIComponent
	{
		private var _app_container:SkinnableContainer;
		private static var _log:ILogger = Log.getLogger("org.forever.view.BrokenLine");
		private var _fromPoint:Point;
		private var _toPoint:Point;
		private var _firstRect:BrokenLineRect;
		private var _secondRect:BrokenLineRect;
		private var _thirdRect:BrokenLineRect;
		private var _firstEdge:BrokenLineEdge;
		private var _rect_w:Number = 6; 
		
		private var _startMove:Boolean = false;
		private var _moving:Boolean = false;
		
		private var _currentClickRect:BrokenLineRect;//当前选中的控制点
		
		private var _rectList:ArrayList;//存放所有控制点
		private var _edgeList:ArrayList;//存放所有控制边
		
		private var _brokenTriangle:BrokenTriangle;
		
		////////////顶点u到v////////////
		private var _u:Task;//出发点
		private var _v:Task;//终点
		
		public function BrokenLine()
		{
			_fromPoint = new Point();
			_toPoint = new Point();
		}
		
		
		/**画折线的方法*/
		public function draw():void{
			initPoint();
			initContainer();
			
			_firstRect = new BrokenLineRect();
			_secondRect = new BrokenLineRect();
			_thirdRect = new BrokenLineRect();
			_firstEdge = new BrokenLineEdge();
			
			initFirstRect();
			initSecondRect();
			initThirdRect();
			initFirstEdge();
			
			initTriangle();
			
			//建立矩形关联边
			_firstRect.secondEdge = _firstEdge;
			_secondRect.firstEdge = _firstEdge;
			
			//建立边关联矩形
			_firstEdge.firstRect = _firstRect;
			_firstEdge.secondRect = _secondRect;
			
			//建立矩形关联的矩形
			_firstRect.nextRect = _thirdRect;
			_secondRect.prevRect = _thirdRect;
			_thirdRect.prevRect = _firstRect;
			_thirdRect.nextRect = _secondRect;
			
			//添加顺序导致组件的重叠z轴顺序
			addChild(_firstEdge);
			addChild(_brokenTriangle);
			addChild(_firstRect);
			addChild(_thirdRect);
			addChild(_secondRect);
			_rectList = new ArrayList(new Array(_firstRect,_thirdRect,_secondRect));
			_edgeList = new ArrayList(new Array(_firstEdge));
			
			hideAllRect();
			
			addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
			
		}
		
		/**
		 * 更新第一个控制点的位置
		 */
		public function updateFirstRect():void{
			var ucenterPoint:Point = new Point(u.x+u.width/2,u.y+u.height/2);//出发点中点坐标
			var vcenterPoint:Point = new Point(_firstRect.nextRect.nextRect.x,_firstRect.nextRect.nextRect.y);//结束点中点坐标
			_fromPoint = getLinkPoint(ucenterPoint,vcenterPoint,u);//计算折线的起始点坐标
			_firstRect.x = _fromPoint.x - _firstRect.width;
			_firstRect.y = _fromPoint.y - _firstRect.height/2; 
			_firstRect.refresh();
			_brokenTriangle.draw();
		}
		
		/**
		 * 更新最后一个控制点的位置
		 * */
		public function updateLastRect():void{
			var ucenterPoint:Point = new Point(_secondRect.prevRect.prevRect.x,_secondRect.prevRect.prevRect.y);//出发点中点坐标
			var vcenterPoint:Point = new Point(v.x+v.width/2,v.y+v.height/2);//结束点中点坐标
			_toPoint = getLinkPoint(vcenterPoint,ucenterPoint,v);//计算折线的终点坐标
			_secondRect.x = _toPoint.x;
			_secondRect.y = _toPoint.y - _secondRect.height/2;
			_secondRect.refresh();
			_brokenTriangle.draw();
		}
		
		/**
		 * 计算折线的起始点坐标
		 */
		public function initPoint():void{
			var ucenterPoint:Point = new Point(u.x+u.width/2,u.y+u.height/2);//出发点中点坐标
			var vcenterPoint:Point = new Point(v.x+v.width/2,v.y+v.height/2);//结束点中点坐标
			_fromPoint = getLinkPoint(ucenterPoint,vcenterPoint,u);//计算折线的起始点坐标
			_toPoint = getLinkPoint(vcenterPoint,ucenterPoint,v);//计算折线的终点坐标
		}
		
		public static function getLinkPoint(fromPoint:Point,targetPoint:Point,acrossNode:Task):Point{
			var angle:Number=getAngel(fromPoint,targetPoint);
			/**计算交点与中心点的垂直和水平距离*/
			var distanceX:Number=Math.abs((targetPoint.x-fromPoint.x)*(acrossNode.width/2)/(targetPoint.y-fromPoint.y));
			var distanceY:Number=Math.abs((targetPoint.y-fromPoint.y)*(acrossNode.width/2)/(targetPoint.x-fromPoint.x));
			if(targetPoint.x<fromPoint.x){
				distanceX=-distanceX;
			}
			if(targetPoint.y<fromPoint.y){
				distanceY=-distanceY;
			}
			/**最终xy坐标*/
			var x:Number=0;
			var y:Number=0;
			if(angle>=45&&angle<135){
				x=fromPoint.x+distanceX;
				y=acrossNode.y;
			}else if(angle>=135&&angle<225){
				x=acrossNode.x;
				y=fromPoint.y+distanceY;
			}else if(angle>=225&&angle<315){
				x=fromPoint.x+distanceX;
				y=fromPoint.y+acrossNode.height/2;
			}else{
				x=fromPoint.x+acrossNode.width/2;
				y=fromPoint.y+distanceY;
			}
			return new Point(x,y);
		}
		
		/**获取两点夹角的角度*/
		private static function getAngel(fromPoint:Point,targetPoint:Point):Number{
			/**为了与三角坐标一致，y坐标的值要反过来*/
			/**通过反正切计算弧度*/
			var radian:Number=Math.abs(Math.atan((targetPoint.x-fromPoint.x)/(targetPoint.y-fromPoint.y)));
			/**计算角度*/
			var angle:Number=radian*180/Math.PI;
			if((targetPoint.x>=fromPoint.x)&&(targetPoint.y<=fromPoint.y)) {//0~90区域
				angle=90-angle;
			}else if((targetPoint.x<=fromPoint.x)&&(targetPoint.y<=fromPoint.y)){//90~180区域
				angle=90+angle;
			}else if((targetPoint.x<=fromPoint.x)&&(targetPoint.y>=fromPoint.y)){//180~270区域
				angle=270-angle;
			}else if((targetPoint.x>=fromPoint.x)&&(targetPoint.y>=fromPoint.y)){//270~360区域
				angle=270+angle;
			}
			return angle;
		}
		
		/**隐藏所有的矩形*/
		public function hideAllRect():void{
			for(var i:int=0;i<_rectList.length;i++){
				(_rectList.getItemAt(i) as BrokenLineRect).visible = false;
			}
		}
		
		/**显示所有的矩形*/
		public function showAllRect():void{
			for(var i:int=0;i<_rectList.length;i++){
				(_rectList.getItemAt(i) as BrokenLineRect).visible = true;
			}
		}
		
		/**初始化自身参数*/
		public function mouseDownHandler(e:MouseEvent):void{
			_log.debug("***************点击*****************");
			showAllRect();
		}
		
		/**初始化箭头*/
		public function initTriangle():void{
			_brokenTriangle = new BrokenTriangle();
			_brokenTriangle.fromRect = _firstRect; 
			_brokenTriangle.toRect = _secondRect;
			_brokenTriangle.draw();
		}
		
		/**初始化容器事件*/ 
		public function initContainer():void{
			_app_container.addEventListener(MouseEvent.MOUSE_MOVE,appContainerMouseMoveHandler);
			_app_container.addEventListener(MouseEvent.MOUSE_UP,appContainerMouseUpHandler);
		}
		
		
		/**获取指定两个矩形的距离,AB=√[(x1-x2)²+(y1-y2)²]*/
		public function getDistance(firstRect:BrokenLineRect,secondRect:BrokenLineRect):Number{
			return Math.sqrt(Math.pow(firstRect.x - secondRect.x,2) + Math.pow(firstRect.y - secondRect.y,2));
		}
		
		/**处理拖动180度直线后，去掉左右控制点的方法*/
		public function process180():Boolean{
			if(_currentClickRect.isSplit){//是拆分过的控制点
				var a:Number = getDistance(_currentClickRect,_currentClickRect.prevRect);
				var b:Number = getDistance(_currentClickRect,_currentClickRect.nextRect);
				var c:Number = getDistance(_currentClickRect.prevRect,_currentClickRect.nextRect);
				var cosC:Number=(a*a+b*b-c*c)/(2*a*b);
				//求出控制点拖动时夹角的及时角度
				var acos:Number =(int)(Math.acos(cosC) * 180 / Math.PI);
				_log.debug("*************角度："+acos+"**************");
				if(_currentClickRect.direction==0 && acos<=165){//第一次将控制点拖动时,角度会逐渐变小，小于165度后确定为正方向
					_currentClickRect.direction = 1;
					_log.debug("*************正方向拖动中**************");
				}else if(_currentClickRect.direction==1 && acos>=165){//如果满足正方向拖动后，在往反方向拖动，角度会逐渐变大，大于165度后确定为反方向
					_currentClickRect.direction = -1;
					_log.debug("*************反方向拖动中**************");
				}
				//如果反方向行动，并且角度在指定范围内,去掉前后控制点
				if(_currentClickRect.direction==-1 && acos>=176 && acos<=180){
					_log.debug("*************进入去掉前后控制点范围**************");
					//获取当前控制点矩形的前驱前驱矩形和后继后继矩形
					var prevPrevRect:BrokenLineRect = _currentClickRect.prevRect.prevRect;
					var nextNextRect:BrokenLineRect = _currentClickRect.nextRect.nextRect;
					//将当前控制点矩形的前驱矩形和后继矩形从容器界面中移除
					this.removeChild(_currentClickRect.prevRect);
					this.removeChild(_currentClickRect.nextRect);
					
					_rectList.removeItem(_currentClickRect.prevRect);
					_rectList.removeItem(_currentClickRect.nextRect);
					
					//更新各个控制点的关联关系
					_currentClickRect.prevRect = prevPrevRect;
					_currentClickRect.nextRect = nextNextRect;
					
					prevPrevRect.nextRect = _currentClickRect;
					nextNextRect.prevRect = _currentClickRect;
					
					prevPrevRect.secondEdge = _currentClickRect.secondEdge;
					 
					_currentClickRect.secondEdge.firstRect = prevPrevRect;
					_currentClickRect.secondEdge.drawLine();
					updateRectTop(_currentClickRect.secondEdge);
					
					this.removeChild(_currentClickRect.firstEdge);
					
					_currentClickRect.firstEdge = null;
					_currentClickRect.secondEdge = null;
					_currentClickRect.isSplit = false;
					_currentClickRect.x = (_currentClickRect.prevRect.x + _currentClickRect.nextRect.x)/2;
					_currentClickRect.y = (_currentClickRect.prevRect.y + _currentClickRect.nextRect.y)/2;
					_moving = false;
					_startMove = false;
					_currentClickRect.direction = 0;
					
					//更新箭头引用
					if(_currentClickRect == _brokenTriangle.fromRect){
						_brokenTriangle.fromRect = prevPrevRect;
						_brokenTriangle.draw();
					}
					
					return true;
				}
			}
			return false;
		}
		
		
		public function appContainerMouseMoveHandler(event:MouseEvent):void{
			if(_moving){
				_currentClickRect.x = mouseX;
				_currentClickRect.y = mouseY;
				if(process180())return;				
				_currentClickRect.refresh();
				_brokenTriangle.draw();
				trace("******************移动中***********************");
			}
		}
		
		public function appContainerMouseUpHandler(event:MouseEvent):void{
			if(_moving && null != _currentClickRect){
				_startMove = false;
				_moving = false;
				//_log.debug(_currentClickRect.desc + "结束移动......");
			}
		}
		
		public function addRectEvent(rect:BrokenLineRect):void{
			rect.addEventListener(MouseEvent.MOUSE_DOWN,rectMouseDownHandler);
			rect.addEventListener(MouseEvent.MOUSE_MOVE,rectMouseMoveHandler);
			rect.addEventListener(MouseEvent.MOUSE_UP,rectMouseUpHandler);
		}
		
		/**矩形鼠标释放事件，一旦释放，停止拖动*/
		public function rectMouseUpHandler(event:MouseEvent):void{
			_startMove = false;
			_moving = false;
			//_log.debug(_currentClickRect.desc + "结束移动......");
		}
		
		public function rectMouseDownHandler(event:MouseEvent):void{
			_startMove = true;//点击组件做移动准备
			_moving = false;//并未真正移动 
			_currentClickRect = event.currentTarget as BrokenLineRect;
			_currentClickRect.print();
			//_log.debug(_currentClickRect.desc + "被点击，准备开始移动......坐标：x=" + _currentClickRect.x + "y=" + _currentClickRect.y );
		}
		
		public function rectMouseMoveHandler(event:MouseEvent):void{
			if(_startMove && !_moving){//如果准备好移动
				//既不是头矩形，也不是尾矩形，也没有拆分过
				if(_currentClickRect != _firstRect && _currentClickRect!=_secondRect && !_currentClickRect.isSplit){
					var _newRectOne:BrokenLineRect = createRect();//新增第一个控制点矩形
					//该矩形是当前控制点矩形和前驱矩形的中间矩形
					_newRectOne.x = (_currentClickRect.x + _currentClickRect.prevRect.x)/2;
					_newRectOne.y = (_currentClickRect.y + _currentClickRect.prevRect.y)/2;
					_newRectOne.desc = UIDUtil.createUID();
					//新增第二个控制点矩形,该矩形是当前控制点矩形和后继矩形的中间矩形
					var _newRectTwo:BrokenLineRect = createRect();
					_newRectTwo.x = (_currentClickRect.x + _currentClickRect.nextRect.x)/2;
					_newRectTwo.y = (_currentClickRect.y + _currentClickRect.nextRect.y)/2;
					_newRectTwo.desc = UIDUtil.createUID();
					//获取当前控制点前驱控制点的第二条关联边
					var _secondEdge:BrokenLineEdge = _currentClickRect.prevRect.secondEdge;
					//更新关联边的第一个控制点为当前控制点
					_secondEdge.firstRect = _currentClickRect;
					//更新关联边的第二个控制点为当前控制点的后继控制点
					_secondEdge.secondRect = _currentClickRect.nextRect;
					//更新当前矩形的第二条关联边
					_currentClickRect.secondEdge = _secondEdge;
					//重绘边
					_secondEdge.drawLine();
					updateRectTop(_secondEdge);//将该边的两端控制点置顶
					//新增一条边，建立该节点与前驱节点的边关系
					var _newEdge:BrokenLineEdge = new BrokenLineEdge();
					_newEdge.firstRect = _currentClickRect.prevRect;
					_newEdge.secondRect = _currentClickRect;
					_newEdge.desc = UIDUtil.createUID();
					
					_newEdge.drawLine();
					
					addChild(_newEdge);
					addChild(_newRectOne);
					addChild(_newRectTwo);
					
					updateRectTop(_newEdge);
					
					//更新当前控制点矩形的前驱矩形的关联边为新边
					_currentClickRect.prevRect.secondEdge = _newEdge;
					//更新当前控制点矩形的第一条关联边
					_currentClickRect.firstEdge = _newEdge;
					
					//更新控制点矩形之间的引用关系
					_currentClickRect.prevRect.nextRect = _newRectOne;
					_currentClickRect.nextRect.prevRect = _newRectTwo;
					
					_newRectOne.prevRect = _currentClickRect.prevRect;
					_newRectOne.nextRect = _currentClickRect;
					
					_newRectTwo.prevRect = _currentClickRect;
					_newRectTwo.nextRect = _currentClickRect.nextRect;
					
					_currentClickRect.prevRect = _newRectOne;
					_currentClickRect.nextRect = _newRectTwo;
					
					_currentClickRect.isSplit = true;//标记为已拆分
					
					//添加到集合中
					_rectList.addItem(_newRectOne);
					_rectList.addItem(_newRectTwo);
					
					_edgeList.addItem(_newEdge);
					
					if(_currentClickRect.nextRect.nextRect == _secondRect){//如果满足这种关联
						_brokenTriangle.fromRect = 	_currentClickRect;//更新箭头的引用
						_brokenTriangle.draw();
					}
					
				}
				_moving = true;
				_log.debug(_currentClickRect.desc + "移动中......坐标：x=" + _currentClickRect.x + "y=" + _currentClickRect.y);
			}
		}
		
		/**创建一个新的矩形点*/
		public function createRect():BrokenLineRect{
			var _newRect:BrokenLineRect = new BrokenLineRect();
			_newRect.width = _rect_w;
			_newRect.height = _rect_w;
			_newRect.setStyle("borderColor","#70B2EE");
			addRectEvent(_newRect);
			return _newRect;
		}
		
		/**更新指定边的两端矩形置顶*/
		public function updateRectTop(_edge:BrokenLineEdge):void{
			this.setChildIndex(_edge.firstRect,this.numChildren-1);
			this.setChildIndex(_edge.secondRect,this.numChildren-1);
		}
		
		/**初始化第一个端点到中点的边*/
		public function initFirstEdge():void{
			_firstEdge.firstRect = _firstRect;
			_firstEdge.secondRect = _secondRect;
			_firstEdge.desc = UIDUtil.createUID();
			_firstEdge.drawLine();
		}
		
		/**初始化中点矩形*/
		public function initThirdRect():void{
			_thirdRect.width = _rect_w;
			_thirdRect.height = _rect_w;
			_thirdRect.setStyle("borderColor","#70B2EE");
			_thirdRect.x = (_firstRect.x + _secondRect.x)/2;
			_thirdRect.y = (_firstRect.y + _secondRect.y)/2;
			_thirdRect.desc = "_thirdRect";
			addRectEvent(_thirdRect);
		}
		
		/**初始化第二个端点的矩形*/
		public function initSecondRect():void{
			_secondRect.width = _rect_w;
			_secondRect.height = _rect_w;
			_secondRect.x = _toPoint.x;
			_secondRect.y = _toPoint.y - _secondRect.height/2;
			_secondRect.setStyle("borderColor","#70B2EE");
			_secondRect.desc = "_secondRect";
			_secondRect.visible = true;
			addRectEvent(_secondRect);
		}
		
		/**初始化第一个端点的矩形*/
		public function initFirstRect():void{
			_firstRect.width = _rect_w;
			_firstRect.height = _rect_w;
			_firstRect.x = _fromPoint.x - _firstRect.width;
			_firstRect.y = _fromPoint.y - _firstRect.height/2;
			_firstRect.setStyle("borderColor","#70B2EE");
			_firstRect.desc = "_firstRect";
			addRectEvent(_firstRect);
		}
		
		/******************* get and set ******************/
		
		/**线终点*/
		public function get toPoint():Point
		{
			return _toPoint;
		}

		/**
		 * @private
		 */
		public function set toPoint(value:Point):void
		{
			_toPoint = value;
		}

		/**线起点*/
		public function get fromPoint():Point
		{
			return _fromPoint;
		}

		/**
		 * @private
		 */
		public function set fromPoint(value:Point):void
		{
			_fromPoint = value;
		}

		/**显示所有可变组件的容器*/
		public function get app_container():SkinnableContainer
		{
			return _app_container;
		}

		/**
		 * @private
		 */
		public function set app_container(value:SkinnableContainer):void
		{
			_app_container = value;
		}

		public function get moving():Boolean
		{
			return _moving;
		}

		public function set moving(value:Boolean):void
		{
			_moving = value;
		}

		public function get u():Task
		{
			return _u;
		}

		public function set u(value:Task):void
		{
			_u = value;
			_u.outEdges.addItem(this);
		}

		public function get v():Task
		{
			return _v;
		}

		public function set v(value:Task):void
		{
			_v = value;
			_v.inEdges.addItem(this);
		}

		
	}
}
